iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0

除了滑鼠外,鍵盤也是使用者必用的輸入設備。在 Compose for Desktop 裡,以下三個地方會與鍵盤互動有關:

  1. 當使用者在 TextField 輸入內容時,透過註冊 onValueChange 事件來更新顯示,讀者可參考 Day 10 的筆記回顧一下。
  2. 在設定 MenuBarItem 元件時,可以透過 shortcut 參數綁定鍵盤快速鍵,讀者可參考 Day 8 的筆記回顧一下。
  3. 若元件有 onKeyEventonPreviewKeyEvent 參數可綁定事件的話可以直接傳入 Event Handler 設定對應的動作。若沒有這兩個參數的話,還是可以透過 Modifier 註冊這兩個事件來綁定鍵盤行為。

今天耕讀筆記,會針對第三點的鍵盤事件做研究。

綁定元件的鍵盤事件屬性

Compose 的 WindowDialog 兩個元件本身就有 onKeyEventonPreviewKeyEvent 參數可綁定事件,由於事件是直接跟整個視窗或對話框綁定,因此元件不需要是當下的焦點就能隨時觸發。

val keys = remember {
    mutableStateMapOf(
        "ctrl" to false,
        "option" to false,
        "shift" to false,
        "meta" to false,
    )
}

Window(onCloseRequest = ::exitApplication, title = "Keyboard Event Basic Setting", onKeyEvent = {
    if (it.type == KeyEventType.KeyDown && (it.key == Key.CtrlLeft || it.key == Key.CtrlRight)) {
        keys["ctrl"] = true
    }
    if (it.type == KeyEventType.KeyDown && (it.key == Key.AltLeft || it.key == Key.AltRight)) {
        keys["option"] = true
    }
    if (it.type == KeyEventType.KeyDown && (it.key == Key.ShiftLeft || it.key == Key.ShiftRight)) {
        keys["shift"] = true
    }
    if (it.type == KeyEventType.KeyDown && (it.key == Key.MetaLeft || it.key == Key.MetaRight)) {
        keys["meta"] = true
    }
    if (it.type == KeyEventType.KeyUp) {
        keys["ctrl"] = false
        keys["option"] = false
        keys["shift"] = false
        keys["meta"] = false
    }
    true
}) {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Row(
            modifier = Modifier.fillMaxSize(),
            horizontalArrangement = Arrangement.Center,
            verticalAlignment = Alignment.CenterVertically,
        ) {
            Text(
                text = "^",
                fontSize = 100.sp,
                color = if (keys["ctrl"] == true) Color.Red else Color.Gray,
            )

            Text(
                text = "⌥",
                fontSize = 100.sp,
                color = if (keys["option"] == true) Color.Red else Color.Gray,
            )

            Text(
                text = "⇧",
                fontSize = 100.sp,
                color = if (keys["shift"] == true) Color.Red else Color.Gray,
            )

            Text(
                text = "⌘",
                fontSize = 100.sp,
                color = if (keys["meta"] == true) Color.Red else Color.Gray,
            )
        }
    }
}

在上面的例子裡,筆者在畫面上放了三個 Text 表示鍵盤上 Ctrl、Option、Shift 及 Meta 四種按鍵,當 Window 收到 onPreviewKeyEvent 時,會更動 keys Map 裡的狀態,進而改變 Text 的顏色。所以當按鍵被按下時,對應的 Text 就會亮起來。

使用 Modifier 綁定鍵盤事件

若元件沒有事件參數可供綁定,還是可以透過 Modifier 為元件綁定鍵盤事件。鍵盤事件有兩個:onKeyEventonPreviewKeyEvent,一般來說會傾向使用 onPreviewKeyEvent 來防止事件被子元件觸發。

var text by remember { mutableStateOf("") }
var sent by remember { mutableStateOf(false) }
    
Column(
    modifier = Modifier.fillMaxSize(),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally,
) {
    TextField(
        value = text,
        onValueChange = { text = it },
        singleLine = true,
        modifier = Modifier.onPreviewKeyEvent {
            if (it.key == Key.Enter && it.type == KeyEventType.KeyDown) {
                text = ""
                sent = true
            }
            if (it.key != Key.Enter && it.type == KeyEventType.KeyDown) {
                sent = false
            }
            false
        }
    )

    Text(
        text = if (sent) "Sent!" else ""
    )
}

在上面的例子裡,筆者用 ModifierTextField 上註冊 onPreviewKeyEvent,當 TextField 是焦點且按下 Enter 鍵時,就會將 TextField 內的文字清空,並在下方顯示 Sent! 字樣。而按下其他按鍵後,Sent! 字樣就會被重設。

KeyKeyEventType

在綁定鍵盤事件時,會用 KeyKeyEventType 來綁定特定的按鍵及狀態。Key 類別已經將鍵盤上所有按鍵設計成屬性方便開發者在 IDE 裡直接選用,而 KeyEventType 一般只會用到兩種:

  • KeyDown:當按鍵按下時。
  • KeyUp:當按鍵抬起時。

透過兩個類別,就組合出複雜的鍵盤按法。

參考資料


上一篇
第 23 天:事件處理之滑鼠互動
下一篇
第 25 天:結合(Multiplatform)Library
系列文
傳教士的 Compose for Desktop 耕讀筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言